<?php
/**
* Schtrack!
*
* This is the application itself ;)
*
* @author Kaloyan K. Tsvetkov <kaloyan@kaloyan.info>
* @license http://opensource.org/licenses/gpl-license.php GNU Public License
* @link http://code.google.com/p/schtrack2/
*/

///////////////////////////////////////////////////////////////////////////////

/**
* {@link Snoopy} is used to download the files of the mirrored website
* @see Snoopy
*/
include __SCHTRACK__ . './schtrack/class.snoopy.php';

/**
* Schtrack
* 
* This class stores the main functionality for this project.
*/
Class schtrack {
	
	/**
	* Configuration Settings
	*
	* These are the default values for the advanced
	* settings, so if omitted from the configuration
	* script, then this set of values will be used instead.
	*
	* @var array
	*/
	var $conf = array(
		'save_dir' => './site/',
		'ttl' => 2592000, /* 30 days */
		);

	/**
	* An instance of {@link Snoopy}, used for downloading the files
	* @var Snoopy
	*/	
	var $sn;
	
	// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
	
	/**
	* Constructor
	*
	* Sets the configuration settings and initiates a {@link Snoopy} object
	*
	* @param array $conf
	*/
	Function schtrack($conf = array()) {
		$this->conf = (array) $conf + $this->conf;
		$this->sn = new Snoopy;
		}

	/**
	* Executes a download of the required URI from the mirrored website
	*/
	Function run() {
		
		// figure out what's the required
		// URI by stripping the path to
		// this application itself
		//
		$url = '/' . preg_replace(
			'~^' . preg_quote($this->conf['self']) . '~',
			'', $_SERVER['REQUEST_URI']
			);

		// get the path where to store the
		// cached copy of the downloaded file
		//
		$path = $this->filename($url);

		$fetch = 0;

		// create the folder for the site, which is mirrored
		//
		if (!is_dir($save_dir = dirname($path))) {
			mkdir($save_dir, 0777);
			}
		
		// a new copy of a file must be fetched
		// if it is either not downloaded yet,
		// or if the cached copy has expired
		//
		if (file_exists($path)) {
			$s = stat($path);
			$fetch = $s['mtime'] + $this->conf['ttl'] < time();
			} else {
			$fetch = 1;
			}

		// make sure NOT to download robots.txt!
		//
		if (false !== strstr($url, 'robots.txt')) {
			readfile(__SCHTRACK__ . './schtrack/robots.txt');
			exit;
			}

		$target = 'http://'
			. $this->conf['source']
			. $url;

		// fetch a new copy of the file, if required
		//
		if ($fetch && $this->sn->fetch($target)) {
		
			@unlink($path);
			file_put_contents($path,
				$this->cook($target)
				);
			}

		readfile($path);
		exit;
		}

	/**
	* Composes the filename for the cached
	* copy of a file from the mirrored website
	*
	* @param string $url
	* @return string
	*/
	Function filename($url) {
		
		$u = parse_url($url) + array(
			'query' => null
			);
		if ($u['query']) {
			$u['query'] = '%3F' . rawUrlEncode($u['query']);
				// ^
				// make sure to encode the question
				// mark and the query string (if any)
			}
		
		$i = pathinfo($u['path']) + array(
			'extension' => 'html',
			);
		$i['dirname'] = ltrim($i['dirname'], '/\\');
		
		if ($u['query']) {
			$u['query'] .= '.' . $i['extension'] ;
				// ^
				// if there is a query string, make
				// sure to append the extension again
			}

		return $this->conf['save_dir']
			. '/' . $this->conf['source'] . '/'
		 	. (!$i['dirname']
		 		? ''
		 		: rawUrlEncode($i['dirname'] . '/')
		 		)

		 	. ($i['basename']
		 		? $i['basename']
		 		: 'index.html'
		 		)

			. $u['query']
			;
		}
	
	/**
	* `Cook` fetched data: do a little `cgi-bin` trick, change the
	* base-href, fix the absolute paths, and append a foot note
	*
	* @param string $url
	* @return string
	*/
	Function cook($url) {

		$content = $this->sn->results;

		$content = str_replace('cgi-bin', ' cgi-bin', $content);
			// ^
			// stupid hack to get around the
			// stupid disadvantage of shared
			// hosting, where you can not
			// disable the `cgi-bin` ScriptAlias

		// it is some sort of text, so ...
		//
		$_h = join('', $this->sn->headers);
		if (false !== stristr($_h, 'Content-Type: text')) {

			// .. change the base href, and ...
			//
			$content = preg_replace('~<body~Uis',
				'<base href="http://'
					. $_SERVER['HTTP_HOST']
					. ltrim($this->conf['self'], '/\\') . '" /><body',
				$content
				);
				
			// ... fix the absolute paths, then ...
			//
			$content = preg_replace('~'
					. preg_quote('http://'
						. $this->conf['source']
						) . '~i',
				'http://'
					. $_SERVER['HTTP_HOST']
					. ltrim($this->conf['self'], '/\\'),
				$content);

			// ... print the footer !
			//
			$_url = preg_replace('~/[^/]+cgi-bin/~Uis', '/cgi-bin/', $url);
			$footer = '<div style="margin: 4px; padding: 2px 4px;
border: solid 1px #b0b000; background:lightyellow; font-family: arial, tahoma,
verdana; position: absolute; top: 0px; left: 0px; display: block; font-size:
11px; cursor:default;">Downloaded by <strong><a style="text-transform:none;"
href="http://code.google.com/p/schtrack2/">Schtrack!</a></strong>
[' . date('r') . '] &rarr; <a href="' . $_url . '" target="_blank"
style="text-transform:none;"><code>' . $_url . '</code></a></div>';
			$content .= $footer;
			}
		
		return $content;
		}
	
	//--end-of-class--
	}
